package io.jboot.fly.controller;

import com.jfinal.aop.Before;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Page;
import io.jboot.Jboot;
import io.jboot.core.cache.JbootCache;
import io.jboot.fly.Constants;
import io.jboot.fly.interceptor.NeedUser;
import io.jboot.fly.manager.ViewCountManager;
import io.jboot.fly.model.*;
import io.jboot.fly.service.*;
import io.jboot.fly.utils.EsThreadUtils;
import io.jboot.fly.utils.JsoupUtils;
import io.jboot.utils.StringUtils;
import io.jboot.web.controller.JbootController;
import io.jboot.web.controller.annotation.RequestMapping;
import io.jboot.web.controller.validate.CaptchaValidate;
import io.jboot.web.controller.validate.EmptyValidate;
import io.jboot.web.controller.validate.Form;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.joda.time.DateTime;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;
import java.util.stream.Collectors;

@RequestMapping(value = "/upload", viewPath = "/WEB-INF/htmls/upload")
public class UserAttachmentController extends JbootController {
    // 当有文件添加进队列时 通过文件名查看该文件是否上传过 上传进度是多少
    private static final String FILE_UPLOAD = "uploads";
    private static JbootCache jbcache = Jboot.me().getCache();
    @Inject
    UserAttachmentService userAttachmentService;
    @Inject
    PostService postService;
    @Inject
    CommentService commentService;
    @Inject
    UserService userService;
    @Inject
    CategoryService categoryService;
    @Inject
    AttachmentCategory AttachmentCategory;
    @Inject
    UserActionService userActionService;
    /**
     * 获取 登陆用户
     *
     * @return
     */
    protected User getLoginedUser() {
        return getAttr(Constants.ATTR_USER);
    }
    public void selectProgressByFileName(String fileName) {
        String jindutiao = "0";
        if (ObjectUtils.anyNotNull(fileName)) {
            jindutiao = ObjectUtils.toString(Jboot.me().getCache().get(FILE_UPLOAD,"jindutiao_" + fileName));
        }
        renderText("{jindutiao :'" + jindutiao + "'}");
    }

    public void fileSave()  throws ServletException, IOException{
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload sfu = new ServletFileUpload(factory);
        sfu.setHeaderEncoding("utf-8");

        String savePath = getRequest().getRealPath("");
        //String folad = "uploads";
        //savePath = savePath + "\\" + folad + "\\";
        savePath = savePath + "/"+FILE_UPLOAD+"/" + getLoginedUser().getId() + "/";
        String fileMd5 = null;
        String chunk = null;
        String fileName = null;
        try {
            List<FileItem> items = sfu.parseRequest(getRequest());

            for (FileItem item : items) {
                fileName = item.getName();
                if (item.isFormField()) {
                    String fieldName = item.getFieldName();
                    if (fieldName.equals("fileMd5")) {
                        fileMd5 = item.getString("utf-8");
                    }
                    if (fieldName.equals("chunk")) {
                        chunk = item.getString("utf-8");
                    }
                } else {
                    File file = new File(savePath + "/" + fileMd5);
                    if (!file.exists()) {
                        file.mkdir();
                    }
                    File chunkFile = new File(savePath + "/" + fileMd5 + "/"
                            + chunk);
                    FileUtils.copyInputStreamToFile(item.getInputStream(),
                            chunkFile);

                }
            }

        } catch (FileUploadException e) {
            e.printStackTrace();
            renderJson(Ret.ok().set("message", "上传失败"));
        }
        renderJson(Ret.ok().set("message", "上传成功"));
    }


    public void mergeOrCheckChunks()throws ServletException, IOException {
        String savePath = getRequest().getRealPath("");

        //String folad = "uploads";
        savePath = savePath + "/"+FILE_UPLOAD+"/" + getLoginedUser().getId() + "/";

        String action = getRequest().getParameter("action");
        String jindutiao = getRequest().getParameter("jindutiao");
        String fileName = getRequest().getParameter("fileName");
        if (action.equals("mergeChunks")) {
            // 合并文件
            // 需要合并的文件的目录标记
            String fileMd5 = getRequest().getParameter("fileMd5");

            // 读取目录里的所有文件
            File f = new File(savePath + "/" + fileMd5);
            File[] fileArray = f.listFiles(new FileFilter() {
                // 排除目录只要文件
                public boolean accept(File pathname) {
                    if (pathname.isDirectory()) {
                        return false;
                    }
                    return true;
                }
            });

            // 转成集合，便于排序
            List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
            Collections.sort(fileList, new Comparator<File>() {
                public int compare(File o1, File o2) {
                    if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2
                            .getName())) {
                        return -1;
                    }
                    return 1;
                }
            });
            // UUID.randomUUID().toString()-->随机名
            File outputFile = new File(savePath + "/" + fileName );
            // 创建文件
            outputFile.createNewFile();
            // 输出流
            FileChannel outChnnel = new FileOutputStream(outputFile).getChannel();
            // 合并
            FileChannel inChannel;
            for (File file : fileList) {
                inChannel = new FileInputStream(file).getChannel();
                inChannel.transferTo(0, inChannel.size(), outChnnel);
                inChannel.close();
                // 删除分片
                file.delete();
            }
            outChnnel.close();
            // 清除文件夹
            File tempFile = new File(savePath + "/" + fileMd5);
            if (tempFile.isDirectory() && tempFile.exists()) {
                tempFile.delete();
            }
            System.out.println("合并成功");
            jbcache.remove(FILE_UPLOAD, "jindutiao_" + fileName);
            renderJson(Ret.ok().set("message", "合并成功"));
        } else if (action.equals("checkChunk")) {
            // 检查当前分块是否上传成功
            String fileMd5 = getRequest().getParameter("fileMd5");
            String chunk = getRequest().getParameter("chunk");
            String chunkSize = getRequest().getParameter("chunkSize");
            jbcache.put(FILE_UPLOAD, "jindutiao_" + fileName, jindutiao);
            File checkFile = new File(savePath + "/" + fileMd5 + "/" + chunk);

            //getResponse().setContentType("text/html;charset=utf-8");
            // 检查文件是否存在，且大小是否一致
            if (checkFile.exists()
                    && checkFile.length() == Integer.parseInt(chunkSize)) {
                // 上传过
                renderText("{\"ifExist\":1}");
                //getResponse().getWriter().write("{\"ifExist\":1}");
            } else {
                // 没有上传过
                //getResponse().getWriter().write("{\"ifExist\":0}");
                renderText("{\"ifExist\":0}");
            }
        }
        //renderText(json);
        //return json;
    }

    public void downFile() {
        try {
            HttpServletResponse response = getResponse();
            HttpServletRequest request = getRequest();
            String savePath = getRequest().getRealPath("");

            String userAttachmentId = request.getParameter("userAttachmentId");
            UserAttachment ua = userAttachmentService.findById(userAttachmentId);
            Post post = postService.findById(ua.getRelPostId());
            //File file = new File(request.getRealPath("") + "\\"+FILE_UPLOAD+"\\"+ getLoginedUser().getId() + "\\" + fileName);
            File file = new File(ua.getAttachmentLocal());
            if (!file.exists()) {
                //addMessage(redirectAttributes, "您要下载的资源已被删除！");
                //return "redirect:" + GlobalConfig.getAdminPath() + "/recorder/data/downloadList/?repage";
                renderJson(Ret.fail().set("message", "您要下载的资源已被删除！"));
            }
            download(response, request, file);

            UserAction userAction = new UserAction();
            userAction.setAction(UserAction.ACTION_UPLOAD);
            userAction.setUserId(getLoginedUser().getId());
            userAction.setPostId(post.getId());
            List<UserAction> userActions = userActionService.findByUserIdPostIdAction(
                    getLoginedUser().getId(),post.getId(),UserAction.ACTION_UPLOAD);
            if(userActions==null ||userActions.size()==0){
                userActionService.save(userAction);
            }
        } catch (Exception e) {
            //logger.error("file download failure：", e);
            e.printStackTrace();
        }
        // return null;
    }

    private void download(HttpServletResponse response, HttpServletRequest request, File file) {
        InputStream in = null;
        ServletOutputStream out = null;
        try {
            int fSize = Integer.parseInt(String.valueOf(file.length()));
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/x-download");
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("Content-Length", String.valueOf(fSize));
            // 防止中文乱码
            response.setHeader("Content-Disposition",
                    "attachment;fileName=" + new String(file.getName().getBytes(), "ISO-8859-1"));
            in = new FileInputStream(file);
            long pos = 0;
            if (null != request.getHeader("Range")) {
                // 断点续传
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                try {
                    pos = Long.parseLong(request.getHeader("Range").replaceAll("bytes=", "").replaceAll("-", ""));
                } catch (NumberFormatException e) {
                    pos = 0;
                }
            }
            out = response.getOutputStream();
            String contentRange = new StringBuffer("bytes ").append(pos + "").append("-").append((fSize - 1) + "")
                    .append("/").append(fSize + "").toString();
            response.setHeader("Content-Range", contentRange);
            in.skip(pos);
            byte[] buffer = new byte[1024 * 10];
            int length = 0;
            while ((length = in.read(buffer, 0, buffer.length)) != -1) {
                out.write(buffer, 0, length);
            }
        } catch (Exception e) {
            //logger.error("file download failure：", e);
            e.printStackTrace();
        } finally {
            try {
                if (null != out) {
                    out.flush();
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                // logger.error("IO Exception：", e);
                e.printStackTrace();
            }
        }

    }

    /**
     * 显示帖子详情
     */
    public void index() {
        String id = getPara();
        if (StringUtils.isBlank(id)) {
            renderError(404);
            return;
        }

        Post post = postService.findById(id);
        UserAttachment userAttachment = userAttachmentService.findByRelPostId(id);
        if (post == null || !post.canShow()) {
            renderError(404);
            return;
        }
        if (userAttachment == null ) {
            renderError(404);
            return;
        }
        setAttr("userAttachment", userAttachment);

        // 记录文章浏览量
        ViewCountManager.me().incr(id);

        userService.join(post, "user_id");
        categoryService.join(post, "category_id");

        int pageNumber = getParaToInt("page", 1);
        pageNumber = pageNumber < 1 ? 1 : pageNumber;

        Page<Comment> page = commentService.paginateByPostId(pageNumber, 10, post.getId());
        userService.join(page, "user_id");

        setAttr("pageData", page);

        setAttr("post", post);
        render("content.html");
    }

    @EmptyValidate({
            @Form(name = "attachmentName", message = "附件名称不能为空"),
            @Form(name = "attachmentInstruction", message = "附件说明不能为空"),
    })
    public void saveUserAttachment(String attachemenTitle ,String attachmentName ,int attachmentSize,String attachmentInstruction,String attachementCategoryId,String id,String categoryId){

        String content = JsoupUtils.clear(attachmentInstruction);
        String title = JsoupUtils.getText(attachemenTitle);

        Post dbPost = null;
        UserAttachment userAttachment = null;
        if (id != null) {
            dbPost = postService.findById(id);
            userAttachment = userAttachmentService.findByRelPostId(id);
        }

        boolean updateAction = dbPost != null;



        final Post post = updateAction ? dbPost : new Post();
        final UserAttachment userAttach = updateAction ? userAttachment : new UserAttachment();

        post.setUserAgent(getUserAgent());
        post.setUserIp(getIPAddress());
        post.setTitle(title);
        post.setContent(content);
        String editmode = getPara("editmode");
        editmode = editmode!=null?editmode:"";
        switch (editmode){
            case "markdown":
                post.setEditMode(Post.EDIT_MODE_MARKDOWN);
                break;
            case "html":
                post.setEditMode(Post.EDIT_MODE_HTML);
                break;
            default: //默认是html
                post.setEditMode(Post.EDIT_MODE_HTML);
        }
        post.setCategoryId(categoryId);
        post.setCommentCount(0L);
        post.setStatus(Post.STATUS_NORMAL); //默认正常发帖
        String userAttachId = StringUtils.uuid();
        userAttach.setId(userAttachId);
        if (!updateAction) {
            post.setUserId(getLoginedUser().getId());
            post.setId(StringUtils.uuid()); // 如果是在RPC默认下，这个ID是不会自动生成的，但是可以提前设置
            post.setPayPoint(0);
            post.setUserattachmentId(userAttachId);
            post.setUserattachementType(attachementCategoryId);
        }


        boolean success = updateAction ? postService.update(post) : postService.save(post);


        if (!success) {
            setFlashAttr("message", "系统错误，请联系管理员。");
            redirect("/upload/content");
        }else{
            new Thread(new EsThreadUtils(updateAction?EsThreadUtils.UPDATE_POST_INDEX:EsThreadUtils.CREATE_POST_INDEX,post)).start();
        }




        userAttach.setRelUserId(getLoginedUser().getId());
        userAttach.setAttachmentName(attachmentName);
        userAttach.setAttachmentSize(attachmentSize/1024);
        userAttach.setAttachmentTitle(attachemenTitle);
        userAttach.setAttachmentLocal(getRequest().getRealPath("") + "/"+FILE_UPLOAD+"/" +
                getLoginedUser().getId() + "/"+attachmentName);
        userAttach.setAttachmentType(attachmentName.substring(attachmentName.lastIndexOf(".")+1));
        userAttach.setCreatedTime(DateTime.now().minusDays(7).toDate());
        userAttach.setAttachmentInstruction(attachmentInstruction);
        userAttach.setRelPostId(post.getId());
        userAttach.setRelTypeId(attachementCategoryId);
        boolean success2 = userAttachmentService.save(userAttach);


        if (success2) {
            setFlashAttr("message", "资源发布成功！");
            redirect("/upload/" + post.getId());
        } else {
            setFlashAttr("message", "系统错误，请联系管理员。");
            redirect("/upload/share");
        }
        //render("content.html");
        return;
    }
    public void attachmentList(){
        keepPara();
        int pageNumber = getParaToInt("page", 1);
        String userId = getPara();
        Page<UserAttachment> page = userAttachmentService.paginateByParams(pageNumber,10,userId);
        setAttr("pageData", page);
        render("user_attachement.html");
    }
    @Before(NeedUser.class)
    public void share(){
        keepPara();
        List<Category> categories_gx =categoryService.findAll().stream().filter
                ((Category c)->"分享".equals(c.getName())).collect(Collectors.toList());
        List<AttachmentCategory> attachementCategorys = AttachmentCategory.findAll();
        setAttr("categories", categories_gx);
        setAttr("attachementCategorys", attachementCategorys);

        String id = getPara();
        if (StringUtils.isBlank(id)) {
            render("share.html");
            return;
        }


        Post post = postService.findById(id);
        UserAttachment userAttachment = userAttachmentService.findByRelPostId(id);
        if (post == null) {
            render("share.html");
            return;
        }
       if(userAttachment==null){
           render("share.html");
           return;
       }

        setAttr("post", post);
        setAttr("userAttachment", userAttachment);


        render("share.html");
    }
    public void content(){
        render("content.html");
    }

    public void myUploadCount(String postId) {

        List<UserAction> ua =userActionService.findByPostAndAction(postId, UserAction.ACTION_UPLOAD);
        int uploadCount = ua!=null?ua.size():0;
        renderText(uploadCount+"");
    }
}
